petitcomputerfandomcom-20200214-history
Talk:Memo/@comment-5334617-20140912000910
Your bug is an interesting one. But before I get to it, I'll say there is a redundancy in line 18: IF KEYBOARD THEN IF KEYBOARD!=0 THEN GOSUB @TYPE IF expression THEN ... will do the same as IF (expression)!=0 THEN .... So, this line can be abbreviated to IF KEYBOARD!=0 THEN GOSUB @TYPE or IF KEYBOARD THEN GOSUB @TYPE whichever you prefer. But, I'll recommend another change to line 18 anyway, later. Now, to the bug. It also manifests when the user taps one of the five 'function keys' at the top of the touchscreen, and sometimes when the user taps 'tab'. The main problem comes from the inconsistency in using different systems to check if something has happened on the keyboard (KEYBOARD on line 18) and what has happened on the keyboard (INKEY$() on line 67). I don't think you have a choice about using INKEY$() on line 67 (unless you want to make your own keyboard pretty much from scratch), so you'll have to change line 18. But it's not as simple as changing it to IF INKEY$()!="" THEN GOSUB @TYPE. That's because of the way INKEY$() works. When a character key is tapped (i.e. a key other than 'backspace', 'shift' and the like), the character gets added to a keyboard buffer, and if the key is kept down, it gets added again regularly as per the auto-repeat feature. INKEY$() will check the buffer, rather than the keyboard directly: if the buffer is empty, INKEY$() will return the empty string; if the buffer is not empty, it removes just one key event from the buffer (the first one, the oldest one) and returns it. All the rest of the events in the buffer will remain, until the next call to INKEY$(). That's how the bug manifests: if the buffer contains "55555", and you type "6", it gets added to the buffer: "555556", and one event is taken out of the buffer ("5") leaving "55556". The next four keypresses will also appear to be "5", no matter what they actually are, and the "6" will not appear until it comes out of the front of the buffer, by which time there are more key characters behind it. So, not reading INKEY$() often enough is a problem: a backlog of key events accumulates. Also, reading it too often is a problem: if the buffer has just one key event, two successive reads of INKEY$() will give two different results - first, the key, and second, the empty string. So you need to use only the INKEY$() system for both the if (line 18) and the what (line 67), but you can't use INKEY$() itself twice - you'll run into the problem just described, the second time, you'll always get the empty string. The solution is, you need your own keyboard buffer, of one character. It could go something like this: for line 18: I$=INKEY$():IF I$!="" THEN GOSUB @TYPE then, in line 67 in the subroutine @TYPE, use I$ instead of INKEY$(). This causes another problem. The 'backspace' key is not detected by INKEY$(), so the code for handling the backspace key (line 66) cannot be in the subroutine @TYPE that's only triggered by INKEY$(). Take line 66, and instead put it just after line 18 (but remove the last RETURN from the line, since we're moving it from inside a subroutine to outside). There are still some problems: if you tap the backspace key while holding down the D-pad, sometimes it will trigger the @BACK subroutine, and sometimes it will not. The simplest way to fix this irregularity would probably be to add AND BUTTON() 0 to the guard before CALL @BACK - that way, you can be sure it never will, so at least it's consistent. The 'tab' key is erratic. Also, when the D-pad is down, key events can accumulate faster in the buffer than they get processed, when the auto-repeat kicks in, when function keys are used, or when the tab key is used. But, I think properly fixing these things would require more than I want to write about right now. They are, at least, problems that disappear when the keyboard buffer is emptied; they do not persist indefinitely.